// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2022. All rights reserved.
 * Description: callback function for memory hardware error caused panic
 * Author: Lv Ying
 * Create: 2022-02-09
 */
#include <linux/notifier.h>
#include <linux/memory_error_panic_notify.h>

/* Register of mce panic notifier chain */
static ATOMIC_NOTIFIER_HEAD(mce_panic_chain);

int mce_register_panic_notifier_chain(struct notifier_block *nb)
{
	if (nb == NULL) {
		pr_err("%s failed. nb is NULL\n", __func__);
		return -EINVAL;
	}

	if (nb->notifier_call == NULL) {
		pr_err("%s failed. notifier_call is NULL\n", __func__);
		return -EINVAL;
	}

	pr_notice("%s success. nb: %pK, nb_call: %pS\n",
			__func__, nb, nb->notifier_call);

	return atomic_notifier_chain_register(&mce_panic_chain, nb);
}
EXPORT_SYMBOL_GPL(mce_register_panic_notifier_chain);

/* unregister of mce panic notifier chain */
int mce_unregister_panic_notifier_chain(struct notifier_block *nb)
{
	if (nb == NULL) {
		pr_notice("%s failed. nb is NULL\n", __func__);
		return -EINVAL;
	}

	pr_err("%s success. nb: %pK, nb_call: %pS\n",
			__func__, nb, nb->notifier_call);

	return atomic_notifier_chain_unregister(&mce_panic_chain, nb);
}
EXPORT_SYMBOL_GPL(mce_unregister_panic_notifier_chain);

/* Notify user kernel will mce panic */
void notify_mce_panic(void)
{
	const int cur_cpu = smp_processor_id();

	pr_notice("RAS: in %s, call notify chain before panic.\n", __func__);
	pr_notice("  %s begin on CPU %d\n", __func__, cur_cpu);
	atomic_notifier_call_chain(&mce_panic_chain, 0, NULL);
	pr_notice("%s end on CPU %d\n", __func__, cur_cpu);
}
